<template>
  <div class="">
    <div>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【get】【x-www-form-urlencoded】加密签名</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="getParam">操作按钮
              </el-button>
            </div>
            <div>
              <p>回调结果：{{ responseResult1 }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【post】【json】加密签名（整体加密）</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="postJson">操作按钮
              </el-button>
            </div>
            <div>
              <p>回调结果：{{ responseResult2 }}</p>
            </div>
          </el-card>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【post】【json】加密签名（整体不加密）</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="postJson1">操作按钮
              </el-button>
            </div>
            <div>
              <p>回调结果：{{ responseResult3 }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【post】【formData】加密签名</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="postFormData">操作按钮
              </el-button>
            </div>
            <div>
              <p>回调结果：{{ responseResult4 }}</p>
            </div>
          </el-card>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【post】【formData】上传文件加密签名</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="postFileFormData">
                操作按钮
              </el-button>
            </div>
            <div>
              <div>
                <input type="file" id="fileInput" name="file" required><br><br>
              </div>
              <p>回调结果：{{ responseResult5 }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="12">
          <el-card class="box-card">
            <div slot="header" class="clearfix">
              <span>【post】【x-www-form-urlencoded】加密签名</span>
              <el-button style="float: right; padding: 3px 0" type="text" @click="postUrlEncode">
                操作按钮
              </el-button>
            </div>
            <div>
              <p>回调结果：{{ responseResult6 }}</p>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
  </div>
</template>
<script>
import CryptoJS from 'crypto-js';
import axios from 'axios';
import * as JSRSASign from 'jsrsasign';

export default {
  name: 'Encrypt',
  data() {
    return {
      visible: false,
      key: '0123456789abcdef',
      privateKey: `-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMKmNBO8eGQ1zoz57Q1vk+hngp1U9+/FN/4zRPDCGbTna0cyov1ASIZJPlTQDczpUt+3cRzprbbJpTB4lArn4E2C0foXifiL6KcDBNNfK8+IkdWaUIEuIoZktBx1Zw4CLfBmn4HQ3MKsUpLBext9p3dpi3nHhyMCozahNlQEAn3nAgMBAAECgYASC6fCUkCORP31zFA+ZNZY8nFSgrqyf1DPzHln7kBeqO6Lw28G4yHJVhr+o+ptN9uXozSyXuh2JljRMJL3aKqlSAl21rz5dLhMA3aZEmMhc8EQLC40Vf5ZirVa6xLFzpsQL+eUVisLd/IxOFkKD4mRXBpCJ+AD5zRzqLDKDUINoQJBAP3TEVO+u7hPGrh/DGEO5YMmFMgi8FqyGLY6hvXLQlMvgoLy+p1j9v/+kQlFQvhRYFhZlqzzb5+Q26yj2Y6tlfcCQQDEUUurwohric816PKPaLQrfRlK/JNNs3myIMwcoZCNmF8m8EuZmRGoonZbw9i/1Z5KTZNLssv79DWtY2qsPJuRAkAo3C9v4cZqVyGgDaO6hCFiSWETDrzOfNkJjMZpDv1wUreZyO+bIpqCf0Jt0Z6ERuVRk6pz0QRpFXKnigDdvQflAkAbCyflbVLlnYJR5tkjMEVBiGYnkkuodITbKPF1MDx9hPP2pTuE2TU5icfMNFpzcrXvfmhAEU1QU//g9sUHHQJBAkABQEDHAwvOORAThQCJWMdJxclIfM5ZyVs21FdEVxjY6aRlnMFeDxE82p7EkyrQ/k/Jb3FS56mh4I+IWvixQCgD
-----END PRIVATE KEY-----`,
      getParamApi: '/encrypt/getParam',
      postJsonApi: '/encrypt/test',
      testNoPwd: '/encrypt/testNoPwd',
      postFormDataApi: '/encrypt/formdata',
      postFormDataUploadApi: '/encrypt/file',
      postUrlEncodeApi: '/encrypt/urlencode',
      responseResult: '',
      responseResult1: '',
      responseResult2: '',
      responseResult3: '',
      responseResult4: '',
      responseResult5: '',
      responseResult6: '',
    };
  },
  created() {
  },
  mounted() {
  },
  watch: {},
  computed: {},
  methods: {
    getParam() {
      console.log('getParam');
      let _this = this;
      // 使用axios进行HTTP GET请求
      let name = 'LICZ';
      let value = '这是一段Value';
      let desc = '这是一段DESC';
      this.xuhuoAjax({
        type: 'get',
        url: this.getParamApi,
        params: {name: name, value: value, desc: desc},
        encryptData: ['name'],
        headers: {
          'signData': ['name', 'value'],
        },
        success: function (data) {
          console.log(data);
          _this.responseResult1 = data.data;
        },
      });
    },
    postJson() {
      let _this = this;
      let value = '这是一段Value';
      this.xuhuoAjax({
        type: 'post',
        url: this.postJsonApi,
        data: {uid: 1, name: 'Licz', age: 30},
        params: {value: value},
        encryptData: ['value'],
        alljsonEncrypt: true,
        headers: {
          'Content-Type': 'application/json',
          'signData': ['value']
        },
        success: function (data) {
          _this.responseResult2 = data.data;
        },
      });
    },
    postJson1() {
      let _this = this;
      let value = '这是一段Value';
      this.xuhuoAjax({
        type: 'post',
        url: this.testNoPwd,
        data: {uid: 1, name: 'Licz', age: 30},
        params: {value: value},
        encryptData: ['value'],
        alljsonEncrypt: false,
        headers: {
          'Content-Type': 'application/json',
          'signData': ['value']
        },
        success: function (data) {
          _this.responseResult3 = data.data;
        },
      });
    },
    postFormData() {
      let _this = this;
      let formData = {
        uid: '1',
        name: 'lcz',
        age: '30',
        sex: 1,
      };
      let value = '这是一段Value';
      this.xuhuoAjax({
        type: 'post',
        url: this.postFormDataApi,
        data: formData,
        params: {value: value},
        encryptData: ['uid', 'name', 'age', 'value'],
        headers: {
          'Content-Type': 'multipart/form-data',
          'signData': ['name', 'value', 'age', 'sex'],
        },
        success: function (data) {
          _this.responseResult4 = data.data;
        },
      });
    },
    postFileFormData() {
      let _this = this;
      let value = '这是一段Value';
      let formData = {
        uid: '1',
        name: 'Licz',
        age: '30',
        sex: 1,
        file: fileInput.files[0]
      };
      this.xuhuoAjax({
        type: 'post',
        url: this.postFormDataUploadApi,
        data: formData,
        params: {value: value},
        encryptData: ['uid', 'name', 'age', 'value'],
        headers: {
          'Content-Type': 'multipart/form-data',
          'signData': ['name', 'value', 'age', 'sex'],
        },
        success: function (data) {
          _this.responseResult5 = data.data;
        },
      });
    },
    postUrlEncode() {
      let _this = this;
      let value = '这是一段Value';
      let postData = {
        uid: '1',
        name: 'Licz',
        age: '30',
        sex: 1,
      };
      this.xuhuoAjax({
        type: 'post',
        url: this.postUrlEncodeApi,
        data: postData,
        params: {value: value},
        encryptData: ['uid', 'name', 'age', 'value'],
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'signData': ['value', 'age', 'sex', 'name'],
        },
        success: function (data) {
          _this.responseResult6 = data.data;
        },
      });
    },

    xuhuoAjax(Params) {
      let params = $.extend({
        data: {},
        params: {},
        async: true,
        beforeSend: '',
        headers: {},
        timeout: 30000,
        cache: true,
        FullScreenLoading: false,
        dataType: 'json',
        processData: true,
        encryptData: []
      }, Params);
      if (Params.headers && Params.headers['Content-Type']) {
        params.headers['Content-Type'] = Params.headers['Content-Type'];
      } else {
        params.headers['Content-Type'] = 'application/x-www-form-urlencoded';
      }
      // 判断是否有加密字段
      let encryptDataLen = params.encryptData.length;
      if (encryptDataLen > 0) {
        for (let i = 0; i < encryptDataLen; i++) {
          if (params.data[params.encryptData[i]]) {
            params.data[params.encryptData[i]] = this.encryptStr(params.data[params.encryptData[i]], key);
          }
          if (params.params[params.encryptData[i]]) {
            params.params[params.encryptData[i]] = this.encryptStr(params.params[params.encryptData[i]], key);
          }
        }
      }

      if (params.headers['Content-Type'] === 'application/json') {
        // 先排序params需要签名的 然后将data整体加密 合并签名
        let signFirst = this.issign(Params, params);
        let bodydata = '';
        let waitSignStr = '';
        if (Params.alljsonEncrypt) {
          bodydata = this.encryptStr(JSON.stringify(params.data), key);
          waitSignStr = signFirst ? (signFirst + '&POST_BODY=' + bodydata) : 'POST_BODY=' + bodydata;
        } else {
          bodydata = params.data;
          waitSignStr = signFirst ? (signFirst + '&POST_BODY=' + JSON.stringify(bodydata)) : 'POST_BODY=' + JSON.stringify(bodydata);
        }
        params.data = bodydata;
        params.data = (typeof bodydata === 'string') ? bodydata : JSON.stringify(bodydata);
        params.headers.sign = this.sign(waitSignStr);
      } else {
        //  判断是否有签名
        let signFirst = this.issign(Params, params);
        if (signFirst) {
          params.headers.sign = this.sign(signFirst);
        }
        if (params.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
          params.data = $.param(params.data);
        } else if (params.headers['Content-Type'] === 'multipart/form-data') {
          let formData = new FormData();
          for (let i in params.data) {
            formData.append(i, params.data[i]);
          }
          params.data = formData;
        }
      }
      return this.axiosFun(params).catch(err => {
        throw err;
      });
    },


    axiosFun(params) {
      let _this = this;
      return new Promise((resolve, reject) => {
        axios({
          url: params.url,
          data: params.data,
          params: params.params,
          method: params.type,
          headers: params.headers,
          timeout: params.timeout,
          transformRequest: [(data, headers) =>
              // 确保数据被转换为JSON格式
              typeof data === 'string' ? data : data],
        }).then(data => {

          if (data.data.result) {
            if (data.data.encrypt === 1) {
              data.data.message = _this.decryptStr(data.data.message, key);
              data.data.data = JSON.parse(_this.decryptStr(data.data.data, key) || '{}');
            }
            if (params.success) {
              params.success(data.data);
            }
            resolve(data.data);
          } else if (params.error) {
            params.error(data.data);
            reject(data.data)
          } else {
            resolve(data);
          }
          /*
           * return data.data;
           * resolve(data.data) ;
           */
        }).catch(error => {
          if (params.error) {
            params.error(error);
          }
          reject(error.response?.data || error);
          // throw data.response.data;
        });
      });
    },
    /**
     * 使用AES加密数据
     *
     * @param {string} data - 待加密的数据
     * @param {string} key - 加密使用的密钥
     * @returns {string} - 加密后的Base64编码字符串
     */
    encryptStr(data, key) {
      /*
       * 使用 AES/ECB 加密
       * return CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
       *     iv: CryptoJS.enc.Utf8.parse(''), // 对于ECB模式，IV可以为空或忽略
       *     mode: CryptoJS.mode.ECB,
       *     padding: CryptoJS.pad.Pkcs7
       * }).toString();
       * 使用 AES/CBC 加密
       */
      const iv = CryptoJS.lib.WordArray.random(16);
      const encrypted = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
      // 将 IV 和密文拼接在一起
      return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64);
    },

    /**
     * 使用AES解密数据
     *
     * @param {string} data - Base64编码的待解密数据
     * @param {string} key - 解密使用的密钥
     * @returns {string} - 解密后的原始数据
     */
    decryptStr(data, key) {
      /*
       * var bytes = CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(key), {
       *     iv: CryptoJS.enc.Utf8.parse(''), // 同样地，对于ECB模式，IV可以为空
       *     mode: CryptoJS.mode.ECB,
       *     padding: CryptoJS.pad.Pkcs7
       * });
       * return bytes.toString(CryptoJS.enc.Utf8);
       * AES/CBC解密
       * 将 Base64 数据解码为 WordArray
       */
      const encryptedData = CryptoJS.enc.Base64.parse(data);
      // 提取 IV 和密文
      const iv = CryptoJS.lib.WordArray.create(encryptedData.words.slice(0, 4)); // 前 16 字节是 IV
      const ciphertext = CryptoJS.lib.WordArray.create(encryptedData.words.slice(4)); // 剩余部分是密文
      // 使用 AES/CBC 解密
      const decrypted = CryptoJS.AES.decrypt(
          {ciphertext: ciphertext}, // 密文
          CryptoJS.enc.Utf8.parse(key), // 密钥
          {
            iv: iv, // 使用提取的 IV
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
          }
      );
      let value = decrypted.toString(CryptoJS.enc.Utf8);
      // 返回解密后的字符串
      return value;
    },

    sign(data) {
      // 解析PEM格式的私钥
      const prvKey = JSRSASign.KEYUTIL.getKey(privateKey);
      // 创建一个签名对象并初始化
      const sig = new JSRSASign.KJUR.crypto.Signature({'alg': 'MD5withRSA', 'prov': 'cryptojs/jsrsa'});
      sig.init(prvKey);
      sig.updateString(data);
      // 生成签名
      const sigValueHex = sig.sign();
      // 将签名值从十六进制转换为Base64编码的字符串
      const sigValueB64 = JSRSASign.b64utohex(sigValueHex); // 这里假设sig.sign()返回的是HEX编码，根据实际情况调整
      return JSRSASign.hex2b64(sigValueHex); // 使用jsrsasign提供的辅助函数将HEX转为Base64
    },

    sortJsonAndBuildString(jsonObject) {
      // 将JSON对象的键提取出来并按字典顺序（ASCII）排序
      const sortedKeys = Object.keys(jsonObject).sort();

      // 根据排序后的键构建所需的字符串
      const params = sortedKeys.map(key =>
          // 对于每个键，获取对应的值，并进行URL编码
          `${encodeURIComponent(key)}=${encodeURIComponent(jsonObject[key])}`
      ).join('&');

      return params;
    },

    issign(Params, params) {
      let signLen = (Params.headers && Params.headers.signData) ? Params.headers.signData.length : 0;
      let signobj = {};
      if (signLen > 0) {
        for (let i = 0; i < signLen; i++) {
          signobj[Params.headers.signData[i]] = params.data[Params.headers.signData[i]] ? params.data[Params.headers.signData[i]] : params.params[Params.headers.signData[i]];
        }
        return this.sortJsonAndBuildString(signobj);
      }
      return false;
    },

  }
}
;
</script>

<style scoped lang='less'>
.el-row {
  margin-bottom: 20px;

  &:last-child {
    margin-bottom: 0;
  }
}
</style>
